package org.eclipse.emf.cdo.ui.merge;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOChangeSet;
import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.model.CDOModelConstants;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
import org.eclipse.emf.cdo.eresource.EresourcePackage;
import org.eclipse.emf.cdo.internal.common.id.CDOIDAndVersionImpl;
import org.eclipse.emf.cdo.internal.common.id.CDOIDObjectLongImpl;
import org.eclipse.emf.cdo.internal.common.revision.CDORevisionImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOListFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl;
import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
import org.eclipse.emf.cdo.ui.merge.conflict.extChangedInSourceAndDetachedInTargetConflict;
import org.eclipse.emf.cdo.ui.merge.conflict.extChangedInTargetAndDetachedInSourceConflict;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.ChangedInSourceAndDetachedInTargetConflict;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.ChangedInSourceAndTargetConflict;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.ChangedInTargetAndDetachedInSourceConflict;
import org.eclipse.emf.spi.cdo.DefaultCDOMerger.Conflict;

/**
 * This class generates a sorted lists of merge operations and conflicts based on the CDO Merger results.
 *
 * @author Thomas Halmetschlager
 */
public class CDOChangeSetProcessor {
	

	/** The session. */
	private CDOSession session;
	//Data
	/** The result. */
	private CDOChangeSetData result;
	
	/** The source changes. */
	private CDOChangeSet sourceChanges;
	
	/** The target changes. */
	private CDOChangeSet targetChanges;
	
	/** The conflicts. */
	private Map<CDOID, Conflict> conflicts;
	
	/** The merger. */
	private DefaultCDOUIMerger merger;
	//Tree Data
	/** The added objects. */
	private ArrayList<MergeTreeParent> newLeafs;
	
	/** The changed objects. */
	private  ArrayList<MergeTreeParent> updateLeafs;
	
	/** The deleted objects. */
	private ArrayList<MergeTreeParent> detachedLeafs;
	
	/** The conflict tree. */
	private List<TreeObject> conflictTree;
	
	/**
	 * Gets the conflicts.
	 *
	 * @return the conflicts
	 */
	public Map<CDOID, Conflict> getConflicts() {
		return conflicts;
	}
	
	/**
	 * Sets the conflicts.
	 *
	 * @param conflicts the conflicts
	 */
	public void setConflicts(Map<CDOID, Conflict> conflicts) {
		this.conflicts = conflicts;
	}

	/**
	 * Gets the session.
	 *
	 * @return the session
	 */
	public CDOSession getSession() {
		return session;
	}

	/**
	 * Sets the session.
	 *
	 * @param session the new session
	 */
	public void setSession(CDOSession session) {
		this.session = session;
	}
	
	/**
	 * Gets the source changes.
	 *
	 * @return the source changes
	 */
	public CDOChangeSet getSourceChanges() {
		return sourceChanges;
	}

	/**
	 * Sets the source changes.
	 *
	 * @param sourceChanges the new source changes
	 */
	public void setSourceChanges(CDOChangeSet sourceChanges) {
		this.sourceChanges = sourceChanges;
	}


	/**
	 * Gets the target changes.
	 *
	 * @return the target changes
	 */
	public CDOChangeSet getTargetChanges() {
		return targetChanges;
	}


	/**
	 * Sets the target changes.
	 *
	 * @param targetChanges the new target changes
	 */
	public void setTargetChanges(CDOChangeSet targetChanges) {
		this.targetChanges = targetChanges;
	}
	
	/*public Map<TreeObject, CDOFeatureDelta> getSourceMappedChanges() {
		return sourceMappedChanges;
	}*/


	/*public CDOChangeSetProcessor(CDOChangeSetData result,CDOBranch sourceBranch,CDOBranch targetBranch) {
		newLeafs = new ArrayList<MergeTreeParent>();
		updateLeafs = new ArrayList<MergeTreeParent>();
		detachedLeafs = new ArrayList<MergeTreeParent>();
		this.result = result;
		this.sourceBranch = sourceBranch;
		this.targetBranch = targetBranch;
		sourceMappedChanges  = new HashMap<TreeObject, CDOFeatureDelta>();
		targetMappedChanges = new HashMap<CDOID, CDOFeatureDelta>();
		usedAsSubElement = new ArrayList<CDOFeatureDelta>();
		atachedConflictResources = new ArrayList<MergeTreeObject>();
	}*/
	
	
	/**
	 * Initiates the class members with the given references.
	 * @param result the result of the merge operations
	 * @param merger an reference to the DefaultCDOUIMerger the calling process used.
	 */
	public CDOChangeSetProcessor(CDOChangeSetData result, DefaultCDOUIMerger merger) {
		newLeafs = new ArrayList<MergeTreeParent>();
		updateLeafs = new ArrayList<MergeTreeParent>();
		detachedLeafs = new ArrayList<MergeTreeParent>();
		this.result = result;
		this.merger = merger;
		/*sourceMappedChanges  = new HashMap<TreeObject, CDOFeatureDelta>();
		targetMappedChanges = new HashMap<CDOID, CDOFeatureDelta>();
		usedAsSubElement = new ArrayList<CDOFeatureDelta>();
		atachedConflictResources = new ArrayList<MergeTreeObject>();*/
	}
	
	/**
	 * Initiates the class members with empty lists or null.
	 */
	public CDOChangeSetProcessor() {
		newLeafs = new ArrayList<MergeTreeParent>();
		updateLeafs = new ArrayList<MergeTreeParent>();
		detachedLeafs = new ArrayList<MergeTreeParent>();
		merger = null;
		/*usedAsSubElement = new ArrayList<CDOFeatureDelta>();
		sourceMappedChanges  = new HashMap<TreeObject, CDOFeatureDelta>();
		targetMappedChanges = new HashMap<CDOID, CDOFeatureDelta>();
		atachedConflictResources = new ArrayList<MergeTreeObject>();
		this.result = null;*/
	}
	
	/**
	 * Returns an array of the changed objects.
	 * @return only the changed objects
	 */
	public Object[] getChangeObj() {
		return extractObjectChange(result.getChangedObjects());
	}
	
	/** Returns the result used to generate data.
	 * @return a {@link CDOChangeSetData}
	 */ 
	public CDOChangeSetData getResult() {
		return result;
	}

	/**
	 * Sets the result.
	 *
	 * @param result the new result
	 */
	public void setResult(CDOChangeSetData result) {
		this.result = result;
	}

	/**
	 * Extracts a list of the newly created objects.
	 */
	private void extractNewObjects() {
		for(CDOIDAndVersion x :result.getNewObjects()){
			if(x instanceof CDORevisionImpl){
				CDORevisionImpl rev = (CDORevisionImpl) x;
				CDOID id = rev.getID();
				int version = rev.getVersion();
				CDOIDAndVersion cdoid = new CDOIDAndVersionImpl(id, version);
				
				MergeTreeParent newTreeObj = new MergeTreeParent(rev);
				MergeTreeObject AddChild;
				CDOFeatureDelta featureDelta;
				
				if(sourceChanges.getNewObjects().contains(x)){
					CDORevisionKey attachedRevision = merger.getConRevisionsSource().get(rev);
					featureDelta = merger.getConFeatureSourceResult().get(rev);
					AddChild = new MergeTreeObject(attachedRevision);
					AddChild.setBranch(sourceChanges.getEndPoint());
				}
				else{
					CDORevisionKey attachedRevision = merger.getConRevisionsTarget().get(rev);
					 featureDelta = merger.getConFeatureTargetResult().get(rev);
					AddChild = new MergeTreeObject(attachedRevision);
					AddChild.setBranch(targetChanges.getEndPoint());
				}

				AddChild.setFeature(featureDelta);
				newTreeObj.setBranch(AddChild.getBranch());
				generateNewLeafText(AddChild);
				newTreeObj.addChild(AddChild);
				newLeafs.add(newTreeObj);
			}
		}
	}
	
	/**
	 * Generates the display text of a added object.
	 *
	 * @param treeChild the tree child
	 */
	private void generateNewLeafText(MergeTreeObject treeChild) {
		CDORevisionKey revision = treeChild.getRevision();
		if(revision instanceof CDORevisionDeltaImpl){
			CDORevisionDeltaImpl subRevImpl = (CDORevisionDeltaImpl) revision;
			treeChild.setName("Added to Parent: "+subRevImpl.getEClass().getName()+"["+subRevImpl.getID().toString()+"]");
		}
		
		//Child.setName("")
		
	}
	
	/**
	 * Extracts deleted objects from the result.
	 */
	@SuppressWarnings("restriction")
	private void extractDelObjects() {
		for(CDOIDAndVersion x :result.getDetachedObjects()){
			
			CDOIDAndVersion cdoid = (CDOIDAndVersionImpl) x;
			
			MergeTreeParent newTreeObj = new MergeTreeParent(cdoid);
			MergeTreeObject AddChild;
			CDOFeatureDelta featureDelta;
			
			if(sourceChanges.getDetachedObjects().contains(x)){
				CDORevisionKey attachedRevision = merger.getConRevisionsSource().get(cdoid);
				featureDelta = merger.getConFeatureSourceResult().get(cdoid);
				AddChild = new MergeTreeObject(attachedRevision);
				AddChild.setBranch(sourceChanges.getStartPoint());
			}
			else{
				CDORevisionKey attachedRevision = merger.getConRevisionsTarget().get(cdoid);
				 featureDelta = merger.getConFeatureTargetResult().get(cdoid);
				AddChild = new MergeTreeObject(attachedRevision);
				AddChild.setBranch(targetChanges.getStartPoint());
			}
	
			AddChild.setFeature(featureDelta);
			newTreeObj.setBranch(AddChild.getBranch());
			generateDeleteLeafText(AddChild);
			newTreeObj.addChild(AddChild);
			newTreeObj.setName("Deleted: " + featureDelta.getFeature().getName() +"@"+cdoid);
			detachedLeafs.add(newTreeObj);
		}
		
	}
	
	/**
	 * Generates the display text of a deleted object.
	 *
	 * @param treeChild the tree child
	 */
	private void generateDeleteLeafText(MergeTreeObject treeChild) {
		CDORevisionKey revision = treeChild.getRevision();
		if(revision instanceof CDORevisionDeltaImpl){
			CDORevisionDeltaImpl subRevImpl = (CDORevisionDeltaImpl) revision;
			treeChild.setName("Deleted in Parent: "+subRevImpl.getEClass().getName()+"["+subRevImpl.getID().toString()+"]");
		}
		
		
	}
	/**
	 * Extracts the changed objects from the result.
	 */
	@SuppressWarnings("restriction")
	private void extractChangedObjects() {
		for(CDOIDAndVersion x :result.getChangedObjects()){
			if(x instanceof CDORevisionDeltaImpl){
				CDORevisionDeltaImpl rev = (CDORevisionDeltaImpl) x;
				ArrayList<TreeObject> childs = new ArrayList<TreeObject>();
				boolean foundElements = false;
				
				for(CDOFeatureDelta deltas : rev.getFeatureDeltas()){
					if(deltas instanceof CDOListFeatureDelta){
						MergeTreeParent par = new MergeTreeParent("List Updates");
						
						for(CDOFeatureDelta listfeature:((CDOListFeatureDelta) deltas).getListChanges()){
							if(!merger.getConnectedElements().contains(listfeature)){
								MergeTreeObject child = new MergeTreeObject(rev);
								child.setFeature(listfeature);
								child.setName(generateReadableString(listfeature));
								par.addChild(child);
								
								foundElements = true;
							}
						}
						childs.add(par);
					}else{
						if(!merger.getConnectedElements().contains(deltas)){
							MergeTreeObject child = new MergeTreeObject(rev);
							child.setFeature(deltas);
							child.setName(generateReadableString(deltas));
							childs.add(child);
							foundElements = true;
						}
					}
				}
				
				if(foundElements){
					MergeTreeParent changeParent = new MergeTreeParent(rev);
					String name = rev.getEClass().getName()+"@"+rev.getID().toString();
					changeParent.setName(name);
					for(TreeObject child:childs){
						changeParent.addChild(child);
					}
					updateLeafs.add(changeParent);
				}
			}
		}
	}
	
	/**
	 * Generates the display text of a changed object.
	 *
	 * @param changedObjects the changed objects
	 * @return the object[]
	 */
	private Object[] extractObjectChange(List<CDORevisionKey> changedObjects) {
		ArrayList<Object> retlist = new ArrayList<Object>() ;
		for(CDOIDAndVersion x :result.getChangedObjects()){
			//retlist.add("UPDATE " + x.getID().toString());
			if(x instanceof CDORevisionDeltaImpl){
				CDORevisionDeltaImpl rev = (CDORevisionDeltaImpl) x;
				for(CDOFeatureDelta deltas : rev.getFeatureDeltas()){
					if(deltas instanceof CDOSetFeatureDeltaImpl){
						CDOSetFeatureDeltaImpl setFeature = (CDOSetFeatureDeltaImpl) deltas;
						
						retlist.add("UPDATE " + x.getID().toString()+ " Type: " + setFeature.getType() + " Name: " +setFeature.getFeature().getName() + " Value: " + setFeature.getValue());
					}
					else if (deltas instanceof CDOListFeatureDeltaImpl) {
						CDOListFeatureDeltaImpl listFeature = (CDOListFeatureDeltaImpl) deltas;
						
						for(CDOFeatureDelta del :listFeature.getListChanges()){

							retlist.add("UPDATE " + x.getID().toString()+ " Type: " + listFeature.getType() + " Name: " +listFeature.getFeature().getName() + " Value: " + del.toString());
						}
					}
					else{
					deltas.getType();
					
					//deltas.getFeature();
					retlist.add("UPDATE " + x.getID().toString()+ " " + deltas.getFeature().getName());
					retlist.add("UPDATE " + x.getID().toString()+ " " + deltas.toString());
					//retlist.add();
					}
				}
				//rev.getValue(feature)
			}
		}
		return retlist.toArray();
		
	}


	/**
	 * Generates a list containing the single operations and a list of occured conflicts.
	 * @return a List with TreeObject 
	 */
	public List<TreeObject> generateTree() {
		
		
		
		ArrayList<TreeObject> treeObjects = new ArrayList<TreeObject>();
		//For Merge-operations
		
		//Generate Node Lists
		
		generateNodeLists();
		
		//Add Node Lists
		TreeParent merges = new TreeParent("Merge Operations");
		if(newLeafs.size() != 0){
			TreeParent newObj = new TreeParent("New Objects");
			for(TreeObject x : newLeafs){
					newObj.addChild(x);
			}
			merges.addChild(newObj);
		}
		if(updateLeafs.size() != 0){
			TreeParent changeObj = new TreeParent("Changed Objects");
			for(TreeObject x : updateLeafs){
					changeObj.addChild(x);
			}
			merges.addChild(changeObj);
		}
		if(detachedLeafs.size() !=0){
			TreeParent delObj = new TreeParent("Detached Objects");
			for(TreeObject x : detachedLeafs){
					delObj.addChild(x);
			}
			merges.addChild(delObj);
		}
		
		if(merges.hasChildren()){
			treeObjects.add(merges);
		}
		treeObjects.addAll(conflictTree);
		return treeObjects;
	}
	
	
	/**
	 * Generates a list containing only conflicts.
	 * @return List with {@link TreeObject}
	 */
	public List<TreeObject> generateTreeConflictTree(){
		ArrayList<TreeObject> conflictTree = new ArrayList<TreeObject>();

	ArrayList<MergeTreeParent> removeList = new ArrayList<MergeTreeParent>();
		if(conflicts != null && conflicts.size() > 0){
			TreeParent rootConflict = new TreeParent("Conflicts");
			
			for(CDOID conflcitID : conflicts.keySet()){
				Conflict conflict = conflicts.get(conflcitID);
				ConflictTreeParent treeParent = new ConflictTreeParent("Conflict", conflict);
				
				if(conflict instanceof ChangedInSourceAndTargetConflict){
					ChangedInSourceAndTargetConflict typicalConflict = (ChangedInSourceAndTargetConflict) conflict;
					TreeParent targetNode = new TreeParent("Target change");
					TreeParent srcNode = new TreeParent("Source change");
					
					for(CDOFeatureDelta delta:typicalConflict.getSourceDelta().getFeatureDeltas()){
			            ConflictTreeObject node = new ConflictTreeObject("S", typicalConflict.getSourceDelta());
			            node.setName(generateReadableString(delta));
			            srcNode.addChild(node);
			          }
					for(CDOFeatureDelta delta:typicalConflict.getTargetDelta().getFeatureDeltas()){
		                  ConflictTreeObject node = new ConflictTreeObject("T", typicalConflict.getTargetDelta());
		                  node.setName(generateReadableString(delta));
		                  targetNode.addChild(node);
		                }
					treeParent.addChild(targetNode);
					treeParent.addChild(srcNode);
					
				}
				if(conflict instanceof extChangedInSourceAndDetachedInTargetConflict){
					extChangedInSourceAndDetachedInTargetConflict typicalConflict = (extChangedInSourceAndDetachedInTargetConflict) conflict;
					TreeObject targetNode = new TreeObject("Target: delete");
					
					TreeParent srcNode = new TreeParent("Source Changed");
					
					for(CDOFeatureDelta delta:typicalConflict.getSourceDelta().getFeatureDeltas()){
						ConflictTreeObject node = new ConflictTreeObject("S", typicalConflict.getSourceDelta());
						node.setName(generateReadableString(delta));
						srcNode.addChild(node);
					}
					
					treeParent.addChild(targetNode);
					treeParent.addChild(srcNode);
				}
				if(conflict instanceof extChangedInTargetAndDetachedInSourceConflict){
					extChangedInTargetAndDetachedInSourceConflict typicalConflict = (extChangedInTargetAndDetachedInSourceConflict) conflict;
					TreeParent targetNode = new TreeParent("Target Change");
					TreeObject srcNode = new TreeObject("Source: Delete");
					for(CDOFeatureDelta delta:typicalConflict.getTargetDelta().getFeatureDeltas()){
			            ConflictTreeObject node = new ConflictTreeObject("T", typicalConflict.getTargetDelta());
			            node.setName(generateReadableString(delta));
			            targetNode.addChild(node);
			          }
					//ATTACH Deleted in Source ListChange
					//mappedChanges.get(key)
					//typicalConflict.getID()
					treeParent.addChild(targetNode);
					treeParent.addChild(srcNode);
				}
				
				rootConflict.addChild(treeParent);
			}
			conflictTree.add(rootConflict);
		}
		
		return conflictTree;
	}
	
	/*private TreeObject expandObject(CDOFeatureDelta feature, CDORevisionKey revision){
		
		MergeTreeParent parent = new MergeTreeParent(revision);
		parent.setName("");
		
		if(feature instanceof CDOListFeatureDelta){
			for(CDOFeatureDelta delta:((CDOListFeatureDelta) feature).getListChanges()){
				parent.addChild(expandObject(delta, revision));
			}
		}
		else
		{
			MergeTreeObject leaf = new MergeTreeObject(revision);
			leaf.setFeature(feature);
			leaf.setName(generateReadableString(feature));
			parent.addChild(leaf);
		}
		
		return parent;
	}*/
	/**
	 * Generates a readable string from the feature delta.
	 *
	 * @param feature the feature delta
	 * @return the string
	 */
	private String generateReadableString(CDOFeatureDelta feature){
		if(feature instanceof CDOSetFeatureDeltaImpl){
        	CDOSetFeatureDeltaImpl featureImpl = (CDOSetFeatureDeltaImpl) feature;
        	return("SET "+featureImpl.getFeature().getName() +" Value:" + featureImpl.getValue().toString());
        }
		else if(feature instanceof CDOUnsetFeatureDelta){
        	CDOUnsetFeatureDelta featureImpl = (CDOUnsetFeatureDelta) feature;
        	 return("UNSET "+featureImpl.getFeature().getName() );
        }
		else if(feature instanceof CDOMoveFeatureDelta){
        	CDOMoveFeatureDelta featureImpl = (CDOMoveFeatureDelta) feature;
        	return("MOVE "+featureImpl.getFeature().getName()+" From: "+ featureImpl.getOldPosition()+" To: "+  featureImpl.getNewPosition());
        }
		else if(feature instanceof CDORemoveFeatureDelta){
        	CDORemoveFeatureDelta featureImpl = (CDORemoveFeatureDelta) feature;
        	return("REMOVE "+featureImpl.getFeature().getName() + " Value: "+ featureImpl.getValue()); 
        }
		else if(feature instanceof CDOClearFeatureDeltaImpl){
        	CDOClearFeatureDeltaImpl clear = (CDOClearFeatureDeltaImpl)feature;
        	return("CLEAR "+clear.getFeature().getName());
        }
		else if(feature instanceof CDOContainerFeatureDeltaImpl){
			CDOContainerFeatureDeltaImpl remove = (CDOContainerFeatureDeltaImpl)feature;
			return("Container "+remove.getFeature().getName());
        }
		else if(feature instanceof CDOAddFeatureDeltaImpl)
        {
			CDOAddFeatureDeltaImpl featureImpl = (CDOAddFeatureDeltaImpl) feature;
        	return("Add "+featureImpl.getFeature().getName() +" Value:" + featureImpl.getValue().toString());
        }
		else if(feature instanceof CDOListFeatureDeltaImpl)
        {
          return "List Change";
        }
		else {
			return feature.toString();
		}
	}
	
	/**
	 * Generate readable text.
	 */
	@SuppressWarnings("restriction")
	/*private void filterChangeSet() {
		
		ArrayList<MergeTreeParent> removeList = new ArrayList<MergeTreeParent>();
		for(MergeTreeParent newLeaf: newLeafs){
			CDOBranchPoint addBranch = sourceChanges.getEndPoint();
			for(MergeTreeParent updateLeaf:updateLeafs){
				if(updateLeaf.getRevision() instanceof CDORevisionDelta){
					CDORevisionDelta deltas = (CDORevisionDelta)updateLeaf.getRevision();
					CDOID ChangeforCDOObjID = deltas.getID();
					for(CDOFeatureDelta featuredelta: deltas.getFeatureDeltas()){
						//check if LIST Change
						if(featuredelta instanceof CDOListFeatureDeltaImpl){
							CDOListFeatureDeltaImpl listfeature=(CDOListFeatureDeltaImpl)featuredelta;
							for(CDOFeatureDelta listFeatureDelta : listfeature.getListChanges()){
								//check if Add-Revision
							    if(listFeatureDelta instanceof CDOAddFeatureDeltaImpl){
							    	CDOAddFeatureDeltaImpl addToList = (CDOAddFeatureDeltaImpl)listFeatureDelta;
							    	if( ((CDOID)addToList.getValue()).toString().equals(newLeaf.getCdoid().toString()) ){
							    		//MAP this AddFeature to new Leaf.
							    		sourceMappedChanges.put(newLeaf, addToList);
							    		usedAsSubElement.add(addToList);
							    		MergeTreeObject addSubObject = new MergeTreeObject(updateLeaf.getRevision());
							    		addSubObject.setBranch(addBranch);
							    		addSubObject.setFeature(addToList);
							    		removeList.add(updateLeaf);
							    		
							    	}
								}
							}
						}
					}
				}
			}
		}
		
		
		
		for(MergeTreeParent delleaf: detachedLeafs){
			CDOBranchPoint sourceStart = sourceChanges.getStartPoint();
			delleaf.setBranch(sourceStart);
			CDOID delID = delleaf.getCdoid();
			CDOView myview = session.openView(sourceStart.getBranch(),sourceStart.getTimeStamp());
			CDOObject delobj = myview.getObject(delID);
			CDOIDObjectLongImpl containerID = (CDOIDObjectLongImpl)delobj.cdoRevision().data().getContainerID();
			CDOObject delparentObject = myview.getObject(containerID); 
			EStructuralFeature feature = delobj.eContainingFeature();
			int index =0;
			int FoundIndex = -1;
			for(Object objectsInParent : delparentObject.cdoRevision().data().toArray(delobj.eContainingFeature())){
				
				
				if(objectsInParent instanceof CDOIDObjectLongImpl)
				{
					CDOIDObjectLongImpl objectID = (CDOIDObjectLongImpl) objectsInParent;
					if(objectID.toString().equals(delID.toString())){
						FoundIndex=index;
					}
				}
				index++;
			}
			
			for(MergeTreeParent updateLeaf:updateLeafs){
				if(updateLeaf.getRevision() instanceof CDORevisionDelta){
					CDORevisionDelta deltas = (CDORevisionDelta)updateLeaf.getRevision();
					CDOID ChangeforCDOObjID = deltas.getID();
					if(ChangeforCDOObjID.toString().equals(containerID.toString())){
						for(CDOFeatureDelta featuredelta: deltas.getFeatureDeltas()){
							if(featuredelta instanceof CDOListFeatureDeltaImpl){
								CDOListFeatureDeltaImpl listfeature=(CDOListFeatureDeltaImpl)featuredelta;
								for(CDOFeatureDelta listFeatureDelta : listfeature.getListChanges()){
									//check if deleted
									if(listFeatureDelta instanceof CDORemoveFeatureDeltaImpl){
										
										CDORemoveFeatureDeltaImpl RemoveFromList = (CDORemoveFeatureDeltaImpl)listFeatureDelta;
										if(RemoveFromList.getIndex() == FoundIndex){
											if(RemoveFromList.getFeature() == feature){
												//FOUND ! Add TO Map ! 
												sourceMappedChanges.put(delleaf, RemoveFromList);
												usedAsSubElement.add(RemoveFromList);
												MergeTreeObject subleaf = new MergeTreeObject(updateLeaf.getRevision());
												subleaf.setBranch(sourceStart);
												subleaf.setFeature(RemoveFromList);
												delleaf.addChild(subleaf );
								    			removeList.add(updateLeaf);	
											
											}
										}
										//if( ((CDOID)RemoveFromList.getValue()).toString().equals(delleaf.getCdoid().toString()) ){
								    		//MAP this RemoveFeature to delete Leaf.
								    	//}
									}
								}
							}
						}
					}
				}
			}
			myview.close();
		}

		for(MergeTreeParent rem:removeList){
			try{
				boolean allUsed = true;
				CDORevisionDelta deltas = (CDORevisionDelta)rem.getRevision();
				for(CDOFeatureDelta delta:deltas.getFeatureDeltas()){
					CDOListFeatureDeltaImpl listfeature = (CDOListFeatureDeltaImpl)delta;
					for(CDOFeatureDelta listdelta:listfeature.getListChanges()){
						if(!usedAsSubElement.contains(listdelta)){
							allUsed=false;
						}
					}
				}
				if(allUsed){
					updateLeafs.remove(rem);
				}
			}
			catch(Exception e){
				
			}
		}
		//for(Object rem:removeList){
		//	updateLeafs.remove(rem);
		//}
		//removeList.clear();
		
	}*/
	

	private void generateReadableText() {
		
	/*	for(MergeTreeParent newLeaf:newLeafs){
			//TODO Get Class Name ????? revImpl.getEClass().getName()
			
			CDORevisionImpl revImpl = (CDORevisionImpl)newLeaf.getRevision();
			CDOFeatureDelta fdelta = sourceMappedChanges.get(newLeaf);
			
			String CdoIdStr = newLeaf.getRevision().getID().toString();
			String newObjClassName =revImpl.getEClass().getName();
			newLeaf.setName(newObjClassName + "[" + CdoIdStr+"]");
			
			
			for(TreeObject subTreeObj:newLeaf.getChildren()){
				
				if(subTreeObj instanceof MergeTreeObject){
					MergeTreeObject subTreeMergeObject = (MergeTreeObject)subTreeObj;
					CDORevisionDeltaImpl subRevImpl = (CDORevisionDeltaImpl)subTreeMergeObject.getRevision();
					
					subTreeObj.setName("Added to Parent: "+subRevImpl.getEClass().getName()+"["+subRevImpl.getID().toString()+"]");
				}
			}
		}
		
		for(MergeTreeParent leaf:detachedLeafs){
			//TODO Get Class Name ????? revImpl.getEClass().getName()
			
			//CDORevisionImpl revImpl = (CDORevisionImpl)leaf.getRevision();
			CDOFeatureDelta fdelta = sourceMappedChanges.get(leaf);
			if(fdelta instanceof CDORemoveFeatureDeltaImpl){
				CDORemoveFeatureDeltaImpl remFdelta = (CDORemoveFeatureDeltaImpl) fdelta;
				
			
				String CdoIdStr = leaf.getCdoid().toString();
				String newObjClassName =remFdelta.getFeature().getEType().getName();
				leaf.setName(newObjClassName + "[" + CdoIdStr+"]");
				
				
				for(TreeObject subTreeObj:leaf.getChildren()){
					
					if(subTreeObj instanceof MergeTreeObject){
						MergeTreeObject subTreeMergeObject = (MergeTreeObject)subTreeObj;
						CDORevisionDeltaImpl subRevImpl = (CDORevisionDeltaImpl)subTreeMergeObject.getRevision();
						
						subTreeObj.setName("Deleted in Parent: "+subRevImpl.getEClass().getName()+"["+subRevImpl.getID().toString()+"]");
					}
				}
			}
		}
		
	  for(MergeTreeParent leaf:updateLeafs){
      //TODO Get Class Name ????? revImpl.getEClass().getName()
      
      CDORevisionDeltaImpl revImpl = (CDORevisionDeltaImpl)leaf.getRevision();
      //CDOFeatureDelta fdelta = mappedChanges.get(leaf);
      
      String CdoIdStr = leaf.getRevision().getID().toString();
      String newObjClassName =revImpl.getEClass().getName();
      leaf.setName(newObjClassName + "[" + CdoIdStr+"]");
      
      for(CDOFeatureDelta feature:revImpl.getFeatureDeltas()){
        if(feature instanceof CDOSetFeatureDeltaImpl){
        	CDOSetFeatureDeltaImpl featureImpl = (CDOSetFeatureDeltaImpl) feature;
        	 leaf.addChild(new MergeTreeObject("SET "+featureImpl.getFeature().getName() +" Value:" + featureImpl.getValue().toString()));
        }
        if(feature instanceof CDOUnsetFeatureDelta){
        	CDOUnsetFeatureDelta featureImpl = (CDOUnsetFeatureDelta) feature;
        	 leaf.addChild(new MergeTreeObject("UNSET "+featureImpl.getFeature().getName() ));
        }
        if(feature instanceof CDOMoveFeatureDelta){
        	CDOMoveFeatureDelta featureImpl = (CDOMoveFeatureDelta) feature;
        	 leaf.addChild(new MergeTreeObject("MOVE "+featureImpl.getFeature().getName()+"From:"+ featureImpl.getOldPosition()+"To:"+  featureImpl.getNewPosition()));
        	
        }
        if(feature instanceof CDORemoveFeatureDelta){
        	CDORemoveFeatureDelta featureImpl = (CDORemoveFeatureDelta) feature;
        	 leaf.addChild(new MergeTreeObject("REMOVE "+featureImpl.getFeature().getName() + "Value: "+ featureImpl.getValue()));
        	 
        }
        if(feature instanceof CDOListFeatureDeltaImpl)
        {
          CDOListFeatureDeltaImpl featureImpl = (CDOListFeatureDeltaImpl) feature;
         
          	for(CDOFeatureDelta delta:featureImpl.getListChanges()){
          		if(!usedAsSubElement.contains(delta)){
          			if(delta instanceof CDOClearFeatureDeltaImpl){
          			  CDOClearFeatureDeltaImpl clear = (CDOClearFeatureDeltaImpl)delta;
          			  leaf.addChild(new MergeTreeObject("CLEAR "+clear.getFeature().getName()));
          			  
          			}
          			if(delta instanceof CDORemoveFeatureDeltaImpl){
          				CDORemoveFeatureDeltaImpl remove = (CDORemoveFeatureDeltaImpl)delta;
            			  leaf.addChild(new MergeTreeObject("REMOVE "+remove.getFeature().getName()));
            			  
            			}
          		}
          	}
        }
        
      }
    }
	  
	  for(MergeTreeObject conflictResource:atachedConflictResources){
		  conflictResource.setName("CLEAR From Parent");
	  }
	}

	private void GenText(TreeObject treeObj){
		if(treeObj instanceof MergeTreeParent){
			MergeTreeParent parentTreeObj = (MergeTreeParent) treeObj;
			for(TreeObject subTreeObj:parentTreeObj.getChildren()){
				GenText(subTreeObj);
			}
		}
		if(treeObj instanceof MergeTreeObject){
			
		}*/
	}
	
	/**
	 * Generates the list with all nodes.
	 */
	private void generateNodeLists() {
		
		extractNewObjects();
		extractDelObjects();
		extractChangedObjects();
		//generateTargetMapping();
		conflictTree = generateTreeConflictTree();
		//filterChangeSet();
		generateReadableText();
	}

/*
	private void generateTargetMapping() {
	
		
			for(CDOIDAndVersion detachedLeaf:targetChanges.getDetachedObjects()){
				CDOID delID = detachedLeaf.getID();
				CDOBranchPoint baseBranch;
				if(targetBranch.isMainBranch()){
					baseBranch =targetBranch.getHead();
				}
				else{
					baseBranch=targetBranch.getBase();
				}
				
				long now = session.getRepositoryInfo().getTimeStamp();
			    CDOBranchPoint target = targetBranch.getPoint(now);

			    CDOBranch sourceBranch = this.sourceBranch;
			    CDOBranchPoint source = sourceBranch.getHead();
			      if (source.getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE)
			      {
			        source = sourceBranch.getPoint(now);
			      }
				CDOBranchPoint ancestor = CDOBranchUtil.getAncestor(baseBranch, source);
				CDOView myview = session.openView(ancestor.getBranch(), ancestor.getTimeStamp());
				try{
					CDOObject delobj = myview.getObject(delID);
				
					CDOIDObjectLongImpl containerID = (CDOIDObjectLongImpl)delobj.cdoRevision().data().getContainerID();
					
					CDOObject delparentObject = myview.getObject(containerID); 
					EStructuralFeature feature = delobj.eContainingFeature();
					int index =0;
					int FoundIndex = -1;
					for(Object objectsInParent : delparentObject.cdoRevision().data().toArray(delobj.eContainingFeature())){
						
						
						if(objectsInParent instanceof CDOIDObjectLongImpl)
						{
							CDOIDObjectLongImpl objectID = (CDOIDObjectLongImpl) objectsInParent;
							if(objectID.toString().equals(delID.toString())){
								FoundIndex=index;
							}
						}
						index++;
					}
					for(CDORevisionKey changedObject:targetChanges.getChangedObjects()){
						if(changedObject instanceof CDORevisionDelta){
							CDORevisionDelta deltas = (CDORevisionDelta)changedObject;
							CDOID ChangeforCDOObjID = deltas.getID();
							if(ChangeforCDOObjID.toString().equals(containerID.toString())){
								for(CDOFeatureDelta featuredelta: deltas.getFeatureDeltas()){
									if(featuredelta instanceof CDOListFeatureDeltaImpl){
										CDOListFeatureDeltaImpl listfeature=(CDOListFeatureDeltaImpl)featuredelta;
										for(CDOFeatureDelta listFeatureDelta : listfeature.getListChanges()){
											//check if deleted
											if(listFeatureDelta instanceof CDORemoveFeatureDeltaImpl){
												
												CDORemoveFeatureDeltaImpl RemoveFromList = (CDORemoveFeatureDeltaImpl)listFeatureDelta;
												if(RemoveFromList.getIndex() == FoundIndex){
													if(RemoveFromList.getFeature() == feature){
														//FOUND ! Add TO Map ! 
														targetMappedChanges.put(detachedLeaf.getID(), RemoveFromList);
														//usedAsSubElement.add(RemoveFromList);
													}
												}
												//if( ((CDOID)RemoveFromList.getValue()).toString().equals(delleaf.getCdoid().toString()) ){
										    		//MAP this RemoveFeature to delete Leaf.
										    	//}
											}
										}
									}
								}
							}
						}
					}
				}
				catch(Exception e){
					
				}
				myview.close();
				
			}
		
		
	}
	*/

/*
	public Map<CDOID, CDOFeatureDelta> getTargetMappedChanges() {
		
		return targetMappedChanges;
	}*/


	

}
